package com.cloudpan.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cloudpan.common.CommonConstants;
import com.cloudpan.entity.bo.SysFileCopyOrMv;
import com.cloudpan.entity.bo.SysFileInfoBo;
import com.cloudpan.entity.param.FileClassifyParam;
import com.cloudpan.entity.param.TreeParam;
import com.cloudpan.entity.pojo.SysFileInfo;
import com.cloudpan.common.exception.GlobalExceptionHandler;
import com.cloudpan.entity.vo.SysFileInfoVo;
import com.cloudpan.entity.vo.SysFileTreeVo;
import com.cloudpan.mapper.SysFileInfoMapper;
import com.cloudpan.service.SysFileInfoService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 文件信息 服务实现类
 * </p>
 *
 * @author Code Generator
 * @since 2023-11-07
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class SysFileInfoServiceImpl extends ServiceImpl<SysFileInfoMapper, SysFileInfo> implements SysFileInfoService {

    private final SysFileInfoMapper sysFileInfoMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean create(SysFileInfoBo infoBo) {
        QueryWrapper<SysFileInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("file_name",infoBo.getFileName())
                .eq(!StringUtils.isEmpty(infoBo.getFilePid()),"file_pid", infoBo.getFilePid())
                .eq("folder_type","1")
                .eq("user_id",infoBo.getUserId());
        SysFileInfo one = this.getOne(queryWrapper);
        if (!ObjectUtils.isEmpty(one)){
            throw new GlobalExceptionHandler("当前目录下已存在" + infoBo.getFileName() + "文件夹");
        }
        SysFileInfo sysFileInfo = new SysFileInfo();
        sysFileInfo.setUserId(infoBo.getUserId());
        sysFileInfo.setFilePid(infoBo.getFilePid());
        sysFileInfo.setFileSize(CommonConstants.FOLDER_ZERO);
        sysFileInfo.setFileName(infoBo.getFileName());
        sysFileInfo.setFolderType(CommonConstants.FOLDERTYPE_ONE);
        sysFileInfo.setStatus(CommonConstants.STATUS_ONE);
        return this.save(sysFileInfo);
    }

    @Override
    public Boolean recycle(String userId,String fileId, Boolean isDelete) {
        LambdaQueryWrapper<SysFileInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(SysFileInfo::getUserId,userId)
                .eq(SysFileInfo::getFileId,fileId)
                .eq(SysFileInfo::getDelFlag,"1");
        SysFileInfo fileInfo = sysFileInfoMapper.selectOne(lambdaQueryWrapper);
        if (isDelete){
            fileInfo.setDelFlag("2");
            return sysFileInfoMapper.updateById(fileInfo) > 0;
        }
        //还原文件
        fileInfo.setDelFlag("0");
        return sysFileInfoMapper.updateById(fileInfo) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean rename(SysFileInfoBo infoBo) {
        //获取需要修改的文件夹或文件信息
        SysFileInfo info = new SysFileInfo();
        QueryWrapper<SysFileInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id",infoBo.getUserId())
                .eq("file_pid",infoBo.getFilePid())
                .eq("file_id",infoBo.getFileId());
        SysFileInfo fileinfo = this.getOne(queryWrapper);
        log.info("查到的文件信息:{}",fileinfo);
        if (infoBo.getFolderType().equals(CommonConstants.FOLDERTYPE_ZERO)){
            //修改文件名称
            BeanUtils.copyProperties(infoBo,info);
            return this.updateById(info);
        }else if (infoBo.getFolderType().equals(CommonConstants.FOLDERTYPE_ONE)){
            //修改文件夹名称
            BeanUtils.copyProperties(infoBo,info);
            return this.updateById(info);
        }
        return Boolean.FALSE;
    }


    @Override
    public String delete(String userid, String fid,Boolean isForce) {
        LambdaQueryWrapper<SysFileInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(SysFileInfo::getUserId,userid)
                .eq(SysFileInfo::getFileId,fid);

        SysFileInfo fileInfo = sysFileInfoMapper.selectOne(lambdaQueryWrapper);
        fileInfo.setRecoveryTime(LocalDateTime.now());
        if (isForce){
            fileInfo.setDelFlag("2");
        }
        fileInfo.setDelFlag("1");
        sysFileInfoMapper.updateById(fileInfo);

        return fileInfo.getFileName();
    }

    @Override
    public String renamefile(SysFileInfoBo infoBo) {
        LambdaQueryWrapper<SysFileInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(SysFileInfo::getFileId,infoBo.getFileId())
                .eq(SysFileInfo::getUserId,infoBo.getUserId());
        SysFileInfo fileInfo = sysFileInfoMapper.selectOne(lambdaQueryWrapper);
        String originalName = fileInfo.getFileName();
        String editName = infoBo.getFileName();
        //判断用户是否将原始的后辍名修改
        String editsuff = editName.substring(editName.lastIndexOf("."));
        if (!(editsuff.equals(originalName.substring(originalName.lastIndexOf("."))))){
            throw new GlobalExceptionHandler("无法修改文件的后辍名,请尝试重新修改");
        }
        //TODO 判断当前目录下 是否存在相同的文件名忽略文件后辍


        //修改文件名称
        fileInfo.setFileName(editName);
        sysFileInfoMapper.updateById(fileInfo);
        return originalName;
    }

    @Override
    public List<SysFileTreeVo> listByTree(TreeParam param) {
        //获得一级分类
        List<SysFileTreeVo> firstLevel = getChildrenByPID(param, null);
        //获得下一级分类
        getNextLevel(param,firstLevel);
        return firstLevel;
    }

    @Override
    public Page<SysFileInfoVo> listClassifyPage(FileClassifyParam param) {
        Page<SysFileInfoVo> page = new Page<>();
        Page<SysFileInfoVo> list = sysFileInfoMapper.listClassifyPage(page,param);
        return list;
    }

    @Override
    public Boolean mvFile(SysFileCopyOrMv copyInfo) {
        SysFileInfo sysFileInfo = null;
        //查询移动的目的地是否是文件夹
        sysFileInfo = sysFileInfoMapper.selectById(copyInfo.getToPid());
        if (sysFileInfo.getFileCategory().equals("0")) {
            throw new GlobalExceptionHandler(sysFileInfo.getFileName() + "是一个文件,不能复制到此处");
        }
        sysFileInfo = sysFileInfoMapper.selectById(copyInfo.getId());
        //移动文件之前判断文件夹下是否存在相同名称,若存在则将文件名称 重复次数 + 1
        LambdaQueryWrapper<SysFileInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.like(SysFileInfo::getFileName, sysFileInfo.getFileName())
                .eq(SysFileInfo::getFolderType, "0");
        Long cnt = sysFileInfoMapper.selectCount(lambdaQueryWrapper);
        String name = sysFileInfo.getFileName();
        if (cnt > 0) {
            String suffix = name.substring(name.lastIndexOf("."));
            String prex = name.substring(0, name.lastIndexOf("."));
            sysFileInfo.setFileName(prex + "(" + cnt + 1 + ")" + suffix);
        }
        //是否移动到根目录
        if (StringUtils.isBlank(copyInfo.getToPid())) {
            sysFileInfo.setFilePid(null);
            sysFileInfoMapper.updateById(sysFileInfo);
            return Boolean.TRUE;
        }
        //不是根目录则直接修改(移动)
        sysFileInfo.setFilePid(copyInfo.getToPid());
        sysFileInfoMapper.updateById(sysFileInfo);
        return Boolean.TRUE;
    }

    @Override
    public Boolean copyFile(SysFileCopyOrMv copyInfo) {
        SysFileInfo info = null;
        //查询复制的目的地是否是文件夹
        info = sysFileInfoMapper.selectById(copyInfo.getToPid());
        if (info.getFileCategory().equals("0")) {
            throw new GlobalExceptionHandler(info.getFileName() + "是一个文件,不能复制到此处");
        }
        info = sysFileInfoMapper.selectById(copyInfo.getId());
        //复制文件之前判断文件夹下是否存在相同名称,若存在则将文件名称 重复次数 + 1
        LambdaQueryWrapper<SysFileInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.like(SysFileInfo::getFileName, info.getFileName())
                .eq(SysFileInfo::getFolderType, "0");
        Long cnt = sysFileInfoMapper.selectCount(lambdaQueryWrapper);
        String name = info.getFileName();
        if (cnt > 0) {
            String suffix = name.substring(name.lastIndexOf("."));
            String prex = name.substring(0, name.lastIndexOf("."));
            info.setFileName(prex + "(" + cnt + 1 + ")" + suffix);
        }
        //是否复制到根目录
        if (StringUtils.isBlank(copyInfo.getToPid())) {
            info.setFilePid(null);
            sysFileInfoMapper.insert(info);
            return Boolean.TRUE;
        }
        //不是根目录则直接复制
        info.setFilePid(copyInfo.getToPid());
        sysFileInfoMapper.insert(info);
        return Boolean.TRUE;
    }

    @Override
    public Boolean mvdir(SysFileCopyOrMv copyInfo) {
        //查询移动的文件夹目的地下是否存在相同的文件夹名称
        LambdaQueryWrapper<SysFileInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysFileInfo::getFileId,copyInfo.getId())
                .eq(SysFileInfo::getFolderType,"1");
        SysFileInfo sysFileInfo = sysFileInfoMapper.selectOne(queryWrapper);

        queryWrapper.clear();
        queryWrapper.eq(SysFileInfo::getFilePid,copyInfo.getToPid())
                .eq(SysFileInfo::getFolderType,"1");
        List<SysFileInfo> sysFileInfos = sysFileInfoMapper.selectList(queryWrapper);

        if (!CollectionUtil.isEmpty(sysFileInfos)){
            for (SysFileInfo fileInfo : sysFileInfos) {
                if (fileInfo.getFileName().equals(sysFileInfo.getFileName())) {
                    throw new GlobalExceptionHandler("当前文件夹下存在相同的文件夹名称");
                }
            }
        }
        //修改文件夹的路径
        sysFileInfo.setFilePid(copyInfo.getToPid());
        sysFileInfoMapper.updateById(sysFileInfo);
        return Boolean.TRUE;
    }

    @Override
    public Boolean copydir(SysFileCopyOrMv copyInfo) {
        //查询复制的文件夹目的地下是否存在相同的文件夹名称
        LambdaQueryWrapper<SysFileInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysFileInfo::getFileId,copyInfo.getId())
                .eq(SysFileInfo::getFolderType,"1");
        SysFileInfo sysFileInfo = sysFileInfoMapper.selectOne(queryWrapper);
        queryWrapper.clear();
        queryWrapper.eq(SysFileInfo::getFilePid,copyInfo.getToPid())
                .eq(SysFileInfo::getFolderType,"1");
        List<SysFileInfo> sysFileInfos = sysFileInfoMapper.selectList(queryWrapper);
        if (!CollectionUtil.isEmpty(sysFileInfos)){
            for (SysFileInfo fileInfo : sysFileInfos) {
                if (fileInfo.getFileName().equals(sysFileInfo.getFileName())) {
                    throw new GlobalExceptionHandler("当前文件夹下存在相同的文件夹名称");
                }
            }
        }
        //查询待复制的文件夹下是否存在文件或者子文件夹 (递归)
        queryWrapper.clear();
        queryWrapper.eq(SysFileInfo::getFilePid,copyInfo.getId())
                .in(SysFileInfo::getFolderType,"1","0");
        List<SysFileInfo> fileChildren = sysFileInfoMapper.selectList(queryWrapper);
        ArrayList<SysFileInfo> childrens = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(fileChildren)) {
            for (SysFileInfo fileChild : fileChildren) {
                fileChild.setFilePid(copyInfo.getToPid());
                childrens.add(fileChild);
            }
        }
        //修改父目录的pid路径
        sysFileInfo.setFilePid(copyInfo.getToPid());
        //如果有子目录或子文件 就批量复制地址文件
        sysFileInfoMapper.insert(sysFileInfo);
        if (CollectionUtil.isNotEmpty(childrens)){
            this.saveBatch(childrens);
        }

        return Boolean.TRUE;
    }

    private void getNextLevel(TreeParam condition,List<SysFileTreeVo> firstLevel) {
        //判断当前父级集合不为空
        if(CollectionUtil.isNotEmpty(firstLevel)){
            // 若集合不为空,则循环当前集合
            for(SysFileTreeVo tree: firstLevel){
                //获取每个集合中的SysFileTreeVo对象,并获取当前登陆的id用户和
                List<SysFileTreeVo> children = getChildrenByPID(condition,tree.getFileId());
                tree.setChildren(children);
                //递归调用，获取当前目录的下级目录
                getNextLevel(condition,children);
            }
        }
    }

    private List<SysFileTreeVo> getChildrenByPID(TreeParam param, String parent) {
        List<SysFileTreeVo> children = sysFileInfoMapper.getChildrenByParentId(param,parent);
        return children;
    }


}
